package com.school.information.config;

import com.school.information.core.security.filter.JwtAuthenticationTokenFilter;
import com.school.information.core.security.handler.AccessDeniedHandlerImpl;
import com.school.information.core.security.handler.AuthenticationEntryPointImpl;
import com.school.information.core.security.provider.WechatAppUserAuthenticationProvider;
import com.school.information.core.service.CustomPasswordService;
import com.school.information.core.service.SecurityUserServiceImpl;
import com.school.information.core.service.WechatAppUserServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.RequestMatcher;

import java.util.Arrays;

/*
 * SecuritConfig配置类
 */
@Configuration
@EnableWebSecurity
@EnableMethodSecurity // 开启注解授权功能
@RequiredArgsConstructor
public class SecurityConfig {
    private final JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    private final SecurityUserServiceImpl userDetailsService;
    private final WechatAppUserServiceImpl wechatAppUserService;

    /**
     * 认证失败处理器
     */
    private final AuthenticationEntryPointImpl authenticationEntryPoint;
    private final AccessDeniedHandlerImpl accessDeniedHandler;
    private final RequestMatcher[] requestMatchers;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // 关闭csrf  因为不使用session
        http.csrf(csrf -> csrf.disable());
        // 禁用HTTP响应标头
        http.headers(headers -> headers.frameOptions(frameOptionsConfig -> frameOptionsConfig.disable()));
        //不通过Session获取SecurityContext 基于token，所以不需要session
        http.sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
        // 过滤请求
        http.authorizeHttpRequests(authorize -> authorize
                .requestMatchers(requestMatchers).permitAll()
                .anyRequest().authenticated());
        //对于登录login 注册register 验证码captchaImage 无需拦截 直接访问
//                .antMatchers("/", "/token/captcha").permitAll()
//                // 静态资源，可匿名访问
//                .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
//                .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
        //  除上面外的所有请求全部需要鉴权认证
//                .anyRequest().authenticated();
        // 添加JWT filter
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        //  认证失败处理类
        http.exceptionHandling(
                exceptionHandlingConfigurer -> exceptionHandlingConfigurer
                        .authenticationEntryPoint(authenticationEntryPoint)
                        .accessDeniedHandler(accessDeniedHandler)
        );
        // SpringSecurity设置允许跨域
        http.cors(cors -> cors.disable());
        return http.build();
    }

    /**
     * 静态文件放行
     */
    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().requestMatchers("/staic/**", "/web/**");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new CustomPasswordService();
    }

    /**
     * 设置默认认证提供 用户名密码登录
     */
    @Bean
    public DaoAuthenticationProvider daoAuthenticationProvider() {
        final DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService);
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        return authenticationProvider;
    }


    /**
     * 设置小程序的登录验证方式 openid验证登录 没有密码
     *
     * @return
     */
    @Bean
    public WechatAppUserAuthenticationProvider daoWechatAppUserAuthenticationProvider() {
        final WechatAppUserAuthenticationProvider wechatAppUserAuthenticationProvider = new WechatAppUserAuthenticationProvider();
        wechatAppUserAuthenticationProvider.setUserDetailsService(wechatAppUserService);
        return wechatAppUserAuthenticationProvider;
    }


    // 获取AuthenticationManager（认证管理器），登录时认证使用。 默认UsernamePasswordAuthenticationToken
//    @Bean
//    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
//        return authenticationConfiguration.getAuthenticationManager();
//    }

    /**
     * 如果项目中需要多个不同的认证管理器，需要使用下方的代码，将不同的认证管理器交由providerManager去管理
     *
     * @return
     * @throws Exception
     */
    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        ProviderManager authenticationManager = new ProviderManager(
                Arrays.asList(daoAuthenticationProvider(), daoWechatAppUserAuthenticationProvider())
        );
        return authenticationManager;
    }

}
